package com.adcc.loadsheet.monitor.service;

import com.adcc.aoc.devLib.common.log.Log;
import com.adcc.loadsheet.monitor.entity.*;
import com.adcc.loadsheet.monitor.mapper.mysql.ServerLogMapper;
import com.adcc.loadsheet.monitor.util.AlarmEnum;
import com.adcc.loadsheet.monitor.util.Constant;
import com.adcc.loadsheet.monitor.util.DateTimeUtil;
import com.adcc.loadsheet.monitor.util.SystemConfigFactory;
import com.adcc.loadsheet.monitor.vo.AlarmLogVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service("ServerLogService")
public class ServerLogServiceImpl implements ServerLogService {

    @Autowired
    private ServerLogMapper serverLogMapper;

    @Autowired
    private SystemConfigFactory systemConfigFactory;

    // 未确认告警信息
    private Map<String, AlarmLogVO> unConfirmAlarmMap = Maps.newHashMap();

    // 未确认告警信息
    private Map<String, AlarmLogVO> confirmAlarmMap = Maps.newHashMap();

    /**
     * 保存系统日志
     *
     * @param serverLog
     */
    private void save(ServerLog serverLog) {
        try {
            serverLogMapper.save(serverLog);
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "save() error", ex);
        }
    }

    /**
     * 构建BGS监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildBGSLog(String moduleName, BGSMonitor curStatus, BGSMonitor lastStatus) {
        try {
            // 记录BGS服务切换
            if (lastStatus != null) {
                if (!Strings.isNullOrEmpty(curStatus.getName()) && !Strings.isNullOrEmpty(lastStatus.getName()) &&
                        !curStatus.getName().equals(lastStatus.getName())) {
                    save(new ServerLog(moduleName, LogType.INFO, "BGS SWITCH " + lastStatus.getName() + " TO " + curStatus.getName()));
                }
            }

            // 第一次BGS监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildBGSLog() error", ex);
        }
    }

    /**
     * 构建Database监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildDatabaseLog(String moduleName, DatabaseMonitor curStatus, DatabaseMonitor lastStatus) {
        try {
            // 第一次DATABASE监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildDatabaseLog() error", ex);
        }
    }

    /**
     * 构建MQ监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildMQLog(String moduleName, MQMonitor curStatus, MQMonitor lastStatus) {
        try {
            // 第一次MQ监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildMQLog() error", ex);
        }
    }

    /**
     * 构建AppUpload监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public  void buildAppUploadLog(String moduleName, AppUploadMonitor curStatus, AppUploadMonitor lastStatus) {
        try {
            // 第一次AppUpload监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildAppUploadLog() error", ex);
        }
    }

    /**
     * 构建航信接口监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildAirInfoLog(String moduleName, AirInfoMonitor curStatus, AirInfoMonitor lastStatus) {
        try {
            // 第一次AirInfo监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildAirInfoLog() error", ex);
        }
    }

    /**
     * 构建MsgUpCenter监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildMsgUpCenterLog(String moduleName, MsgUpCenterMonitor curStatus, MsgUpCenterMonitor lastStatus) {
        try {
            // 第一次MsgUpCenter监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildMsgUpCenterLog() error", ex);
        }
    }

    /**
     * 构建website监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildWebsiteLog(String moduleName, WebsiteMonitor curStatus, WebsiteMonitor lastStatus) {
        try {
            // 第一次BGS监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, curStatus.getErrorReason())));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, curStatus.getErrorReason())));
                        break;
                    default:
                        break;

                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildWebsiteLog() error", ex);
        }
    }

    /**
     * 通过比对当前和上一次的舱单程序状态，生成错误日志
     *
     * @param curStatus
     * @param lastStatus
     * @return
     */
    private String getForwarderErrorReason(ForwarderMonitor curStatus, ForwarderMonitor lastStatus) {
        String s = "";
        StringBuilder sb = new StringBuilder();
        if (lastStatus == null) {
            if (!curStatus.isFirstProgramUp() || !curStatus.isFirstUmeInterfaceUp()) {
                sb.append("HOST ").append(curStatus.getFirstHost()).append(":");
                if (!curStatus.isFirstProgramUp()) {
                    sb.append("PROGRAM IS DOWN,");
                }
                if (!curStatus.isFirstUmeInterfaceUp()) {
                    sb.append("UME-INTERFACE IS DOWN,");
                }
            }
            if (!curStatus.isSecondProgramUp() || !curStatus.isSecondUmeInterfaceUp()) {
                sb.append("HOST ").append(curStatus.getSecondHost()).append(":");
                if (!curStatus.isSecondProgramUp()) {
                    sb.append("PROGRAM IS DOWN,");
                }
                if (!curStatus.isSecondUmeInterfaceUp()) {
                    sb.append("UME-INTERFACE IS DOWN,");
                }
            }
        } else {
            if ((curStatus.isFirstProgramUp() != lastStatus.isFirstProgramUp()) || (curStatus.isFirstUmeInterfaceUp() != lastStatus.isFirstUmeInterfaceUp())) {
                sb.append("HOST ").append(curStatus.getFirstHost()).append(":");
                if (curStatus.isFirstProgramUp() != lastStatus.isFirstProgramUp()) {
                    if (curStatus.isFirstProgramUp()) {
                        sb.append("PROGRAM IS UP,");
                    } else {
                        sb.append("PROGRAM IS DOWN,");
                    }
                }
                if (curStatus.isFirstUmeInterfaceUp() != lastStatus.isFirstUmeInterfaceUp()) {
                    if (curStatus.isFirstUmeInterfaceUp()) {
                        sb.append("UME-INTERFACE IS UP,");
                    } else {
                        sb.append("UME-INTERFACE IS DOWN,");
                    }
                }
            }
            if ((curStatus.isSecondProgramUp() != lastStatus.isSecondProgramUp()) || (curStatus.isSecondUmeInterfaceUp() != lastStatus.isSecondUmeInterfaceUp())) {
                sb.append("HOST ").append(curStatus.getSecondHost()).append(":");
                if (curStatus.isSecondProgramUp() != lastStatus.isSecondProgramUp()) {
                    if (curStatus.isSecondProgramUp()) {
                        sb.append("PROGRAM IS UP,");
                    } else {
                        sb.append("PROGRAM IS DOWN,");
                    }
                }
                if (curStatus.isSecondUmeInterfaceUp() != lastStatus.isSecondUmeInterfaceUp()) {
                    if (curStatus.isSecondUmeInterfaceUp()) {
                        sb.append("UME-INTERFACE IS UP,");
                    } else {
                        sb.append("UME-INTERFACE IS DOWN,");
                    }
                }
            }
        }
        s = sb.toString();
        if (s.length() > 0) {
            s = s.substring(0, s.length() - 1);
        }
        return s;
    }

    /**
     * 构建舱单抓取程序监控日志
     *
     * @param curStatus
     * @param lastStatus
     */
    @Override
    public void buildForwarderLog(String moduleName, ForwarderMonitor curStatus, ForwarderMonitor lastStatus) {
        try {
            // 第一次BGS监控日志 或者 状态异常码不一致
            if (lastStatus == null || !curStatus.getErrorCode().equals(lastStatus.getErrorCode())) {
                switch (curStatus.getStatus()) {
                    case NORMAL:
                        save(new ServerLog(moduleName, LogType.INFO, String.format(Constant.LOG_NORMAL, moduleName)));
                        break;
                    case WARNING:
                        save(new ServerLog(moduleName, LogType.WARN, String.format(Constant.LOG_WARNING, moduleName, getForwarderErrorReason(curStatus, lastStatus))));
                        break;
                    case ABNORMAL:
                        save(new ServerLog(moduleName, LogType.ERROR, String.format(Constant.LOG_ABNORMAL, moduleName, "ALL PROGRAM IS DOWN")));
                        break;
                    default:
                        break;
                }
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildForwarderLog() error", ex);
        }
    }

    // --------------------------------------------------▽告警日志数据构建▽---------------------------------------

    /**
     * 构建BGS监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildBGSAlarmLog(String moduleName, BGSMonitor curStatus, BGSMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 告警升级，需要重新告警，即由一般变严重
                if(lastStatus != null){
                    Set<String> reAlarmContents = BGSMonitor.getReAlarmContents(lastStatus.getUplinkStatus(), lastStatus.getDownlinkStatus(),
                                                                                curStatus.getUplinkStatus(), curStatus.getDownlinkStatus());
                    setReAlarmContent(reAlarmContents, moduleName);
                }
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildBGSAlarmLog() error", ex);
        }
    }

    /**
     * 构建Database监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildDatabaseAlarmLog(String moduleName, DatabaseMonitor curStatus, DatabaseMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 告警升级，需要重新告警，即由一般变严重
                if(lastStatus != null){
                    Set<String> reAlarmContents = DatabaseMonitor.getReAlarmContents(lastStatus.getMasterStatus(), lastStatus.getSlaveStatus(), curStatus.getMasterStatus(), curStatus.getSlaveStatus());
                    setReAlarmContent(reAlarmContents, moduleName);
                }
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildDatabaseAlarmLog() error", ex);
        }
    }

    /**
     * 构建MQ监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildMQAlarmLog(String moduleName, MQMonitor curStatus, MQMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 告警升级，需要重新告警，即由一般变严重
                if(lastStatus != null){
                    Set<String> reAlarmContents = MQMonitor.getReAlarmContents(lastStatus.getStatus(), curStatus.getStatus());
                    setReAlarmContent(reAlarmContents, moduleName);
                }
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildMQAlarmLog() error", ex);
        }
    }

    /**
     * 构建AppUpload监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildAppUploadAlarmLog(String moduleName, AppUploadMonitor curStatus, AppUploadMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildAppUploadAlarmLog() error", ex);
        }
    }

    /**
     * 构建航信接口监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildAirInfoAlarmLog(String moduleName, AirInfoMonitor curStatus, AirInfoMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildAirInfoAlarmLog() error", ex);
        }
    }

    /**
     * 构建MsgUpCenter监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildMsgUpCenterAlarmLog(String moduleName, MsgUpCenterMonitor curStatus, MsgUpCenterMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildMsgUpCenterAlarmLog() error", ex);
        }
    }

    /**
     * 构建website监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildWebsiteAlarmLog(String moduleName, WebsiteMonitor curStatus, WebsiteMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildWebsiteAlarmLog() error", ex);
        }
    }

    /**
     * 构建舱单抓取程序监控日志-告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildForwarderAlarmLog(String moduleName, ForwarderMonitor curStatus, ForwarderMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildForwarderAlarmLog() error", ex);
        }
    }

    /**
     * 构建mysql监控告警日志
     *
     * @param curStatus 当前服务状态
     * @param lastStatus 上一次服务状态
     */
    @Override
    public void buildMysqlAlarmLog(String moduleName, MysqlMonitor curStatus, MysqlMonitor lastStatus) {
        try {
            // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
            preventAbnormalAlarm(curStatus.getStatus() ,moduleName);
            // 如果状态码一致，则不处理
            if(lastStatus != null && curStatus.getErrorCode().equals(lastStatus.getErrorCode())){
                return;
            }
            // 第一次监控日志 或者 状态异常码不一致
            if (curStatus.getStatus() == MonitorStatus.NORMAL) {
                updateNormalAlarmLog(moduleName);
            } else {
                // 上一次正常的节点
                Set<String> lastUnAlarmContents = lastStatus != null ? lastStatus.getUnAlarmContent() : new HashSet<>();
                updateAbNormalAlarmLog(moduleName, curStatus.getStatus(), curStatus.getAlarmContent(), curStatus.getUnAlarmContent(), lastUnAlarmContents);
            }
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "buildMysqlAlarmLog() error", ex);
        }
    }

    /**
     * 防止不能正常告警现象
     * 双重防护，在告警确认时，也会对恢复正常的告警进行确认删除
     *
     * （如：未确认的异常恢复正常后，系统弹框，点击确认时，该模块发生了异常，导致无法告警）
     *
     * @param status 当前服务状态
     * @param moduleName 模块名称
     */
    private void preventAbnormalAlarm(MonitorStatus status, String moduleName) {
        // 当模块状态为正常时，如果已确认里包含该模块，则进行删除，预防因并发操作影响下次异常不能正常告警
        if(status == MonitorStatus.NORMAL && confirmAlarmMap.containsKey(moduleName)){
            confirmAlarmMap.remove(moduleName);
        }
    }

    /**
     * 模块告警恢复时，告警信息处理
     * 如果恢复之前，最后一次异常信息未被确认，则依然弹框告警，且告警信息显示最后一次异常信息
     * 如果恢复之前，最后一次异常信息已被确认，则弹框关闭
     *
     * @param moduleName 服务模块名称
     */
    private void updateNormalAlarmLog(String moduleName) {
        if (unConfirmAlarmMap.containsKey(moduleName)) {
            // 最后一次异常信息未被确认，则依然弹框告警，且告警信息显示最后一次异常信息
            AlarmLogVO alarmLogVO = unConfirmAlarmMap.get(moduleName);
            // 整体正常后，显示上一次状态
            alarmLogVO.setLastStatus(alarmLogVO.getStatus());
            alarmLogVO.setStatus(MonitorStatus.NORMAL);
        }
        // 如果没有未确认告警，关闭弹框
        if (confirmAlarmMap.containsKey(moduleName)) {
            confirmAlarmMap.remove(moduleName);
        }
    }

    /**
     * 节点异常级别发生变化，需要重新告警（如：由一般变严重，或者由严重变一般）
     * @param reAlarmContents 需要重新告警的节点
     * @param moduleName 服务模块名称
     */
    private void setReAlarmContent(Set<String> reAlarmContents ,String moduleName) {
        // 节点异常级别发生变化，需要重新告警（如：由一般变严重，或者由严重变一般）
        if(!reAlarmContents.isEmpty() && confirmAlarmMap.containsKey(moduleName)){
            AlarmLogVO confirmVO = confirmAlarmMap.get(moduleName);
            confirmVO.getContent().removeAll(reAlarmContents);
        }
    }

    /**
     * 节点发生异常时处理逻辑
     * 1：异常节点需弹框+声音告警
     * 2：已经弹框但是未确认的异常节点，设置了忽略项，不能自动关闭弹框，需下次异常时生效
     * 3：异常的节点，点击确认后，不再重复告警
     * 4：告警确认后，部分节点正常后又异常需要重新告警
     * 5：忽略项不进行弹框+声音告警
     *
     * @param moduleName 服务模块名称
     * @param status 当前模块服务状态
     * @param curAlarmContent 本模块异常的节点
     * @param curUnAlarmContent 本模块正常的节点（用于判断告警确认后，部分节点正常后又异常需要重新告警）
     * @param lastUnAlarmContent 本模块上一次状态中正常的节点（用于判断上一次节点异常告警后，未点击确认，节点恢复后，再确认，节点又异常需要重新告警）
     */
    private void updateAbNormalAlarmLog(String moduleName, MonitorStatus status, Set<String> curAlarmContent,
                                        Set<String> curUnAlarmContent, Set<String> lastUnAlarmContent) {
        // 3: 异常的节点，点击确认后，不再重复告警
        if(confirmAlarmMap.containsKey(moduleName)){
            AlarmLogVO confirmVO = confirmAlarmMap.get(moduleName);
            //将本次为异常，上次为正常的节点从已确认中移出，重新告警 (现象：上一次节点异常告警后，未点击确认，节点恢复后，再确认，节点又异常后未重新告警)
            Set<String> reAlertContent = getNeedDelContents(confirmVO.getContent(), lastUnAlarmContent);
            confirmVO.getContent().removeAll(reAlertContent);

            // 过滤已确认的节点
            Set<String> needDelAlarm = getNeedDelContents(curAlarmContent, confirmVO.getContent());
            curAlarmContent.removeAll(needDelAlarm);

            // 4：告警确认后，部分节点正常后又异常需要重新告警：节点正常后，先从已确认中移除，下次再异常时，才可以存入未确认列表中
            if(curUnAlarmContent != null && curUnAlarmContent.size() > 0){
                Set<String> needDel = getNeedDelContents(confirmVO.getContent(), curUnAlarmContent);
                confirmVO.getContent().removeAll(needDel);
            }
        }
        // 将剩余未确认的节点信息放入未确认map中
        if(curAlarmContent != null && curAlarmContent.size() > 0){
            // 获取忽略项
            Set<String> ignoreAlarm = systemConfigFactory.getAlarmIgnoreSet();
            if(unConfirmAlarmMap.containsKey(moduleName)){
                // 2：已经弹框但是未确认的异常节点，设置了忽略项，不能自动关闭弹框，需下次异常时生效
                if(ignoreAlarm != null && ignoreAlarm.size() > 0){
                    // 找出本次新增的异常节点
                    AlarmLogVO oldAlarmLogVO = unConfirmAlarmMap.get(moduleName);
                    Set<String> lastContent = getNeedDelContents(curAlarmContent, oldAlarmLogVO.getContent());
                    Set<String> newAlarmContent = new HashSet<>();
                    newAlarmContent.addAll(curAlarmContent);
                    newAlarmContent.removeAll(lastContent);
                    // 从异常节点中移出本次新增异常节点中忽略的节点
                    Set<String> ignoreContent = getIgnoreContent(newAlarmContent, ignoreAlarm);
                    if(ignoreContent != null && ignoreContent.size() > 0){
                        curAlarmContent.removeAll(ignoreContent);
                    }
                }
            }else{
                // 5：忽略项不进行弹框+声音告警(如果之前没有未确认告警，对所有节点进行忽略项判断)
                Set<String> ignoreContent = getIgnoreContent(curAlarmContent, ignoreAlarm);
                if(ignoreContent != null && ignoreContent.size() > 0){
                    curAlarmContent.removeAll(ignoreContent);
                }
            }

            // 1：异常节点需弹框+声音告警
            if(curAlarmContent != null && curAlarmContent.size() > 0){
                AlarmLogVO alarmLogVO = new AlarmLogVO();
                alarmLogVO.setModuleName(moduleName);
                alarmLogVO.setStatus(status);
                alarmLogVO.setContent(curAlarmContent);
                unConfirmAlarmMap.put(moduleName, alarmLogVO);
            }
        }
    }

    /**
     * 判断新增的异常节点是否属于忽略项
     * @param contents 本次新增的异常节点信息
     * @param alarmIgnoreAlarm 忽略项
     */
    private Set<String> getIgnoreContent(Set<String> contents, Set<String> alarmIgnoreAlarm){
        Set<String> ignoreContents = new HashSet<>();
        for(String element : contents){
            if(alarmIgnoreAlarm.contains(element)){
                ignoreContents.add(element);
            }
        }
        return ignoreContents;
    }

    /**
     * 找出需要删除的元素
     * @param curContent 当前需要对比的节点内容
     * @param configContent 被对比的节点内容
     */
    private Set<String> getNeedDelContents(Set<String> curContent ,Set<String> configContent){
        Set<String> needDelContent = new HashSet<>();
        for (String content : curContent) {
            if (configContent.contains(content)) {
                needDelContent.add(content);
            }
        }
        return needDelContent;
    }

    // --------------------------------------------------△告警日志数据构建△---------------------------------------

    // --------------------------------------------------▽告警日志前端显示使用▽-------------------------------------------
    /**
     * 获取告警弹框内容
     *
     * 告警声音：机场地服监控-舱单拆解服务（一般/严重）告警，请及时处理！
     * 弹框告警：舱单拆解服务（一般/严重）告警！XXX异常！XXX异常！
     */
    @Override
    public List<AlarmLogVO> getAlarmContents() throws Exception {
        List<AlarmLogVO> alarmLogVOS = Lists.newArrayList();
        Set<Map.Entry<String, AlarmLogVO>> entries = unConfirmAlarmMap.entrySet();
        if(entries == null || entries.size() == 0 ){
            return alarmLogVOS;
        }

        for (Map.Entry<String, AlarmLogVO> entry : entries) {
            AlarmLogVO alarmLogVO = entry.getValue().clone();

            // 告警恢复正常后，弹窗应该显示最后的警告提醒
            MonitorStatus showStatus = alarmLogVO.getStatus();
            if(alarmLogVO.getStatus() == MonitorStatus.NORMAL){
                showStatus = alarmLogVO.getLastStatus();
            }
            // 模块信息：舱单拆解服务（一般/严重）告警！
            String moduleAlarmInfo = AlarmEnum.getAlarmModelInfo(alarmLogVO.getModuleName(), showStatus);
            alarmLogVO.setModuleAlarmInfo(moduleAlarmInfo);
            // 节点信息：XXX异常！XXX异常！
            alarmLogVO.setAlarmInfo(AlarmEnum.getAlarmShowContent(alarmLogVO.getContent()));
            alarmLogVOS.add(alarmLogVO);
        }
        return alarmLogVOS;
    }

    /**
     * 告警确认
     * 1：异常恢复后，点击确认：[1]如果已确认中有，则删除，未确认表中：删除
     *                            （例：某模块中节点1异常确认后，节点2异常未确认，然后节点1和2都恢复了。）
     * 2：异常告警，点击确认：
     *          [2]已确认中没有该模块信息时：从未确认中删除，添加到已确认中。（例：该模块第一次告警）
     *          [3]已确认中已经存在该模块信息时：判断未确认信息中是否已经存在已确认中，已存在，则合并content内容，从未确认中删除。
     *            （例：某模块节点1异常，确认后，节点2异常，再次确认）
     *
     * @param moduleName 模块名称
     */
    @Override
    public void alarmConfirm(String moduleName) {
        if (!unConfirmAlarmMap.containsKey(moduleName)) {
            return;
        }
        AlarmLogVO unConfirm = unConfirmAlarmMap.get(moduleName);
        // 从未确认中删除
        unConfirmAlarmMap.remove(moduleName);

        // 更新确认中的信息
        if(unConfirm.getStatus() == MonitorStatus.NORMAL){
            // 当前告警状态为正常时，如果确认中有告警信息，则删除
            if(confirmAlarmMap.containsKey(moduleName)){
                confirmAlarmMap.remove(moduleName);
            }
        }else{
            // 当前告警状态为异常时
            if(confirmAlarmMap.containsKey(moduleName)){
                // 已确认中已经有该模块的异常，则将当前异常节点内容合并到已确认节点内容中
                AlarmLogVO confirm = confirmAlarmMap.get(moduleName);
                for (String alarmElement : unConfirm.getContent()) {
                    if (!confirm.getContent().contains(alarmElement)) {
                        confirm.addContent(alarmElement);
                    }
                }
                confirm.setStatus(unConfirm.getStatus());
                confirmAlarmMap.put(moduleName, confirm);
            }else{
                // 将本次确认的异常告警放入确认集合中
                confirmAlarmMap.put(moduleName, unConfirm);
            }
        }
    }

    // --------------------------------------------------△告警日志前端显示△-------------------------------------------

    /**
     * 展示最新系统日志(24小时/3天/1周)
     *
     * @param count 单位：小时
     * @return
     */
    @Override
    public List<ServerLog> showLog(int count) throws Exception {
        try {
            // [2024-06-20：张丽娟：修改日志显示条数，将日志显示条数按照时间段显示]
            String endTime = DateTimeUtil.getNowUTCTimeStr();
            String startTime = DateTimeUtil.getMinusHours(count);
            List<ServerLog> list = serverLogMapper.findTheNewest(startTime, endTime);
            return list;
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "showLog() error", ex);
            throw ex;
        }
    }

    /**
     * 根据条件分页查询系统日志
     *
     * @param serverName
     * @param type
     * @param content
     * @param startTime
     * @param endTime
     * @param currentPage
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<ServerLog> find(String serverName, String type, String content, String startTime, String endTime, int currentPage, int pageSize) throws Exception {
        try {
            String strServerName = Strings.nullToEmpty(serverName);
            String strType = Strings.nullToEmpty(type);
            String strContent = Strings.emptyToNull(content);
            if (!Strings.isNullOrEmpty(strContent)) {
                strContent = "%" + strContent.replace("%", "") + "%";
            }

            String strStartTime = Strings.isNullOrEmpty(startTime) ? "" : startTime + " 00:00:00";

            String strEndTime = Strings.isNullOrEmpty(endTime) ? "" : endTime + " 23:59:59";

            PageHelper.startPage(currentPage, pageSize);

            List<ServerLog> list = serverLogMapper.find(strServerName, strType, strContent, strStartTime, strEndTime);

            PageInfo<ServerLog> pageInfo = new PageInfo<>(list);

            return pageInfo;
        } catch (Exception ex) {
            Log.error(ServerLogService.class, "find() error", ex);
            throw ex;
        }
    }

}
